/* 
         //  // css选择器(字符串)
        new GetEle(".list li");

        // 单个原生dom元素 => 转化为对应的实例化对象
        var first = document.getElementsByClassName("first")[0];
        new GetEle(first);  // [first]

        // 多元素 (传入一个DOM元素的集合) => 转化为对应的实例化对象
        var liList = document.getElementsByTagName("li"); // [li,li,li,li,li,li]
        new GetEle(liList);
    
    */
function GetEle(selector) {
    // {} 
    // {}[[Prototype]] = GetEle.prototype;
    // this -> {}

    // 多样化获取元素 => 将获取的元素放到集合中 
    if (typeof selector == "string") {// ".list li"
        // 接收一个css选择器  把获取的元素集合存储到实例化对象中
        var list = document.querySelectorAll(selector);  // {}.list=[li,li,li,li]
    } else if (selector instanceof Element) {
        // 接收的是单个dom元素 selector => li.first  => 没有集合就自己建一个
        var list = [selector];  // [li.first]  
    } else if (typeof selector == "object" && selector.length >= 0) {
        // 传入一个dom元素的集合   [li,li,li,li]
        var list = selector;
    }

    // list是伪数组 -> 有自己的原型属性[[Prototype]]指向,且改变原型属性指向后 数组结构不存在

    list = Array.from(list); // 转真数组 => 赋值原值

    Object.setPrototypeOf(list, GetEle.prototype); // 既保留数组结构,又能使用GetEle.prototype的方法

    return list;  // list = [li,li,li,li]
}



// text()  获取和设置实例化对象(集合)中的元素的text内容
// text("11111")  => 有内容就设置
// text()         => 没有内容就获取
GetEle.prototype.text = function (con) {
    // this -> 调用此方法的实例化对象   list=[li,li,li,li]
    // arguments -> 函数调用时实际参数的集合   lenth-> 参数的个数
    if (arguments.length >= 1) { // 有至少一个参数 就设置
        // for (var i = 0; i < this.length; i++) {
        //     var ele = this[i];
        //     ele.textContent = con;
        // }

        // this -> 调用此方法的实例化对象 -> 可以使用GetEle.prototype上所有的方法
        this.each((ele, i) => {
            ele.textContent = con;
        })
        return this;
    } else { // 没有参数  获取
        return this[0].textContent;
    }
}

// html()  获取和设置实例化对象(集合)中的元素的html内容
// html("11111")  => 有内容就设置
// html()         => 没有内容就获取
GetEle.prototype.html = function (con) {
    // this -> 调用此方法的实例化对象   list=[li,li,li,li]
    // arguments -> 函数调用时实际参数的集合   lenth-> 参数的个数
    if (arguments.length >= 1) { // 有至少一个参数 就设置
        // for (var i = 0; i < this.length; i++) {
        //     var ele = this[i];
        //     ele.innerHTML = con;
        // }

        this.each((ele, i) => {
            ele.innerHTML = con;
        })
        return this;
    } else { // 没有参数  获取
        return this[0].innerHTML;
    }
}


// val()  获取和设置实例化对象(集合)中的元素的val内容
// val("11111")  => 有内容就设置
// val()         => 没有内容就获取
GetEle.prototype.val = function (con) {
    // this -> 调用此方法的实例化对象   list=[li,li,li,li]
    // arguments -> 函数调用时实际参数的集合   lenth-> 参数的个数
    if (arguments.length >= 1) { // 有至少一个参数 就设置
        // for (var i = 0; i < this.length; i++) {
        //     var ele = this[i];
        //     ele.value = con;
        // }
        this.each((ele, i) => {
            ele.value = con;
        })
        return this;
    } else { // 没有参数  获取
        return this[0].value;
    }
}

// hide()   将实例化对象(集合)中的元素隐藏
// show()   将实例化对象(集合)中的元素隐藏


GetEle.prototype.hide = function (con) {
    // this -> 调用此方法的实例化对象   list=[li,li,li,li]
    // for (var i = 0; i < this.length; i++) {
    //     var ele = this[i];
    //     ele.style.display = "none";
    // }
    this.each((ele, i) => {
        ele.style.display = "none";
    })

    return this;

}

GetEle.prototype.show = function (con) {
    // this -> 调用此方法的实例化对象   list=[li,li,li,li]
    // for (var i = 0; i < this.length; i++) {
    //     var ele = this[i];
    //     ele.style.display = "block";
    // }

    this.each((ele, i) => {
        ele.style.display = "block";
    })
    return this;
}

// 封装的遍历方法
GetEle.prototype.each = function (callback) { // 形参callback接收了一个函数
    // this -> 调用此方法的实例化对象   list=[li,li,li,li]
    // var callback = function (item, index, array) {  // 传入的函数
    //     console.log(item, index, array);
    // }

    // 每次循环执行传入的函数
    for (var i = 0; i < this.length; i++) {
        // this[i]
        // i
        // this
        callback(this[i], i, this);
    }
    return this;
}


// on(type,callback) -> 添加事件监听
GetEle.prototype.on = function (type, callback) {
    // this -> 调用此方法的实例化对象 -> [li,li,li,li,li]
    this.each(function (ele, i) {
        ele.addEventListener(type, callback);
    })
    return this;
}

// 基于on方法二次封装 => 对象事件类型绑定事件
GetEle.prototype.click = function (callback) {
    // this -> 调用此方法的实例化对象 -> [li,li,li,li,li]
    this.on("click", callback);
    return this;
}
GetEle.prototype.dblclick = function (callback) {
    // this -> 调用此方法的实例化对象 -> [li,li,li,li,li]
    this.on("dblclick", callback);
    return this;
}
GetEle.prototype.mousedown = function (callback) {
    // this -> 调用此方法的实例化对象 -> [li,li,li,li,li]
    this.on("mousedown", callback);
    return this;
}


// off(type,callback) -> 删除事件监听
GetEle.prototype.off = function (type, callback) {
    // this -> 调用此方法的实例化对象 -> [li,li,li,li,li]
    this.each(function (ele, i) {
        ele.removeEventListener(type, callback);
    })
    return this;
}

// css()   获取和设置集合中元素的样式
// css("width","200px")  有两个参数就设置
// css({width: "200px",height: "200px"})  传入一个对象参数进行设置

// css("width")          有一个参数就获取
GetEle.prototype.css = function (cssKey, cssVal) {
    // this -> 调用此方法的实例化对象 -> [li,li,li,li,li]
    if (arguments.length >= 2) {  // 有两个参数就设置
        this.each(function (ele, i) {
            ele.style[cssKey] = cssVal;
        })
        return this;

    } else if (arguments.length >= 1) { // 有一个参数就获取
        // 有一个参数  -> cssKey接收 (字符串/对象)

        if (typeof cssKey == "string") {
            // 多元素默认获取集合中的第一个
            var ele = this[0];
            if (window.getComputedStyle) {
                return window.getComputedStyle(ele)[cssKey];
            } else {
                return ele.currentStyle[cssKey];
            }
        } else if (typeof cssKey == "object") {
            // cssKey => 对象 => {width: "200px",height: "200px"}
            for (var key in cssKey) {
                var val = cssKey[key];
                // this.each(function (ele, i) {
                //     ele.style[key] = val;
                // })
                this.css(key, val);
            }

            return this;


        }

    } else {
        // 创建一个错误对象  -> 包含错误提示
        var err = new Error("Please pass in at least one parameters");
        throw err;  // 抛出错误 -> 代码将会显示红色报错 -> 后续代码也不执行
    }
}


// width()  获取和设置集合中元素的宽度
// width("200px")  width("200")  有参数就设置
// width()         没有参数就获取
GetEle.prototype.width = function (val) {
    //  this -> 调用此方法的实例化对象 -> [li,li,li,li,li]
    if (arguments.length >= 1) { // 有参数就设置
        // val 宽度的具体值
        // 有单位  => 直接设置  200.55 px % pt em rem vw vh vmin vmax
        // 没有单位 默认px单位   200 => px

        var reg = /(px|%|pt|em|rem|vw|vh|vmin|vmax)$/
        if (reg.test(val)) {  //以 px等单位中的一个结尾
            this.css("width", val);  //设置宽度
        } else {
            this.css("width", val + "px");
        }
        return this;
    } else { // 没有参数就获取
        return parseFloat(this.css("width"));   //取值时去单位
    }
}


// height()  获取和设置集合中元素的宽度
// height("200px")  height("200")  有参数就设置
// height()         没有参数就获取
GetEle.prototype.height = function (val) {
    //  this -> 调用此方法的实例化对象 -> [li,li,li,li,li]
    if (arguments.length >= 1) { // 有参数就设置
        // val 宽度的具体值
        // 有单位  => 直接设置  200.55 px % pt em rem vw vh vmin vmax
        // 没有单位 默认px单位   200 => px

        var reg = /(px|%|pt|em|rem|vw|vh|vmin|vmax)$/
        if (reg.test(val)) {  //以 px等单位中的一个结尾
            this.css("height", val);  //设置宽度
        } else {
            this.css("height", val + "px");
        }

        return this;
    } else { // 没有参数就获取
        return parseFloat(this.css("height"));   //取值时去单位
    }
}

// attr()   获取和设置集合中元素的属性节点
// attr("class","one two three")  两个参数就设置
// attr("class")  一个参数就获取
GetEle.prototype.attr = function (key, val) {
    //  this -> 调用此方法的实例化对象 -> [li,li,li,li,li]
    if (arguments.length >= 2) {
        this.each((ele, i) => {
            ele.setAttribute(key, val);
        })
        return this;
    } else if (arguments.length >= 1) {
        // 如果有多个参数默认返回集合中的第一个
        return this[0].getAttribute(key);
    } else {
        // 创建一个错误对象  -> 包含错误提示
        var err = new Error("Please pass in at least one parameters");
        throw err;  // 抛出错误 -> 代码将会显示红色报错 -> 后续代码也不执行
    }

}

// prop()   获取和设置集合中元素节点的内置属性 (property   Object.defineProperty())
// prop("className", "one two three")  两个参数就设置  ele.className = "xxx"
// prop("className")  一个参数就获取   ele.className
GetEle.prototype.prop = function (key, val) {
    //  this -> 调用此方法的实例化对象 -> [li,li,li,li,li]
    if (arguments.length >= 2) {
        this.each((ele, i) => {
            ele[key] = val;
        })
        return this;
    } else if (arguments.length >= 1) {
        // 如果有多个参数默认返回集合中的第一个
        return this[0][key];
    } else {
        // 创建一个错误对象  -> 包含错误提示
        var err = new Error("Please pass in at least one parameters");
        throw err;  // 抛出错误 -> 代码将会显示红色报错 -> 后续代码也不执行
    }
}

// $(".list li").eq(2).css({ backgroundColor: "red" })

// eq(index)  传入一个下标,返回对应下标元素形成的实例化对象  
GetEle.prototype.eq = function (index) {
    //  this -> 调用此方法的实例化对象  -> [li,li,li,li,li]
    var ele = this[index];  //先获取对应下标的元素 
    return $(ele); // [li]  // 转化为GetEle的实例化对象 -> 后面可以继续使用 Get.prototype上的方法
}


//  $(".list li").eq(2).siblings().css({ backgroundColor: "blue" });

// siblings()  除了被选中元素以外 所有的同级元素
GetEle.prototype.siblings = function () {
    //  this -> 调用此方法的实例化对象  -> [li]
    var ele = this[0]; //被选中的元素
    var parentEle = ele.parentElement;
    var children = parentEle.children;

    // 从所有子元素中 排除自己 => 除了被选中元素以外 所有的同级元素
    var list = Array.from(children).filter(item => item !== ele);

    return $(list);
}

// index()  返回被选中的元素相对于同级的下标
GetEle.prototype.index = function () {
    //  this -> 调用此方法的实例化对象  -> [li]
    var ele = this[0]; //被选中的元素
    var parentEle = ele.parentElement;
    var children = parentEle.children;

    // 从所有子元素中 排除自己 => 除了被选中元素以外 所有的同级元素
    var index = Array.from(children).findIndex(item => item == ele);

    return index;
}

// 传入一个csss选择器 根据传入的参数快速获取实例化对象
function $(selector) {  //  ".list li"
    return new GetEle(selector);  // new GetEle(".list li")
}